package org.dtrd.modules.record.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.dtrd.common.util.DateUtils;
import org.dtrd.config.system.Constant;
import org.dtrd.modules.message.util.MsgEventPusher;
import org.dtrd.modules.patient.entity.bean.report.ReportDrugSuggest;
import org.dtrd.modules.record.entity.bean.SigninSuggestBean;
import org.dtrd.modules.record.entity.bean.SigninSuggestDailyInfo;
import org.dtrd.modules.record.entity.po.DtrdEntRdSigninSuggest;
import org.dtrd.modules.record.entity.request.DailyRequest;
import org.dtrd.modules.record.mapper.DtrdEntRdSigninSuggestMapper;
import org.dtrd.modules.record.service.IDtrdEntRdSigninSuggestService;
import org.dtrd.modules.suggest.entity.po.DtrdEntRdDoctorSigninSuggestCategory;
import org.dtrd.modules.suggest.service.IDtrdEntRdDoctorSigninSuggestCategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static org.dtrd.config.system.Constant.RecordType.valueOf;

/**
 * <p>
 * 打卡建议 服务实现类
 * </p>
 *
 * @author QR
 * @since 2021-10-21
 */
@Service
@DS("multi-datasource1")
public class DtrdEntRdSigninSuggestServiceImpl extends ServiceImpl<DtrdEntRdSigninSuggestMapper, DtrdEntRdSigninSuggest> implements IDtrdEntRdSigninSuggestService {

    @Autowired
    private MsgEventPusher msgPusher;
    @Resource
    private IDtrdEntRdDoctorSigninSuggestCategoryService suggestCategoryService;

    @Override
    public SigninSuggestBean getSuggestByPatientIdAndType(Integer patientId, Integer type) {
        LambdaQueryWrapper<DtrdEntRdSigninSuggest> wrapper = Wrappers.lambdaQuery(DtrdEntRdSigninSuggest.class)
                .eq(DtrdEntRdSigninSuggest::getPatientId, patientId)
                .eq(DtrdEntRdSigninSuggest::getSigninType, type)
                .orderByDesc(DtrdEntRdSigninSuggest::getCreateTime)
                .last("limit 1");
        DtrdEntRdSigninSuggest po = getOne(wrapper);
        return Optional.ofNullable(po).map(p -> new SigninSuggestBean().parseFromPO(p)).orElse(null);
        // return Optional.ofNullable(po).map(p -> {
        //     String typeText = Optional.ofNullable(p.getSigninType()).map(id -> suggestCategoryService.getById(id)).map(DtrdEntRdDoctorSigninSuggestCategory::getCategoryName).orElse(null);
        //     p.setSigninTypeText(typeText);
        //     return new SigninSuggestBean().parseFromPO(p);
        // }).orElse(null);
    }

    @Override
    public List<SigninSuggestBean> getSuggestByPatientIdAndTypes(Integer patientId, Integer... type) {
        List<Integer> types = Arrays.stream(type).collect(Collectors.toList());
        List<DtrdEntRdSigninSuggest> suggests = baseMapper.selectSuggestByPatientIdAndTypes(patientId, types);
        // 返回一个 signType : 建议对象 的 map , 就不用多次查询了
        if (CollectionUtil.isNotEmpty(suggests)) {
            return suggests.stream().map(p -> new SigninSuggestBean().parseFromPO(p)).collect(Collectors.toList());
            // return suggests.stream().filter(Objects::nonNull).map(p -> {
            //     String typeText = Optional.ofNullable(p.getSigninType()).map(id -> suggestCategoryService.getById(id)).map(DtrdEntRdDoctorSigninSuggestCategory::getCategoryName).orElse(null);
            //     p.setSigninTypeText(typeText);
            //     return new SigninSuggestBean().parseFromPO(p);
            // }).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public Map<Integer, String> getDailySuggest(Integer patientId, Date date, Integer... suggestTypes) {
        List<Integer> types = Arrays.stream(suggestTypes).collect(Collectors.toList());
        List<DtrdEntRdSigninSuggest> suggests = baseMapper.selectDailySuggest(patientId, date, types);
        if (CollectionUtil.isNotEmpty(suggests)) {
            HashMap<Integer, String> map = new HashMap<>();
            for (DtrdEntRdSigninSuggest suggest : suggests) {
                map.put(suggest.getSigninType(), suggest.getSuggestContent());
            }
            return map;
        }
        return null;
    }

    @Override
    public Map<String, List<DtrdEntRdSigninSuggest>> getWeeklySuggestMap(Integer patientId, Date startDate, Date endDate, Integer... suggestTypes) {
        List<Integer> types = Arrays.stream(suggestTypes).collect(Collectors.toList());
        List<DtrdEntRdSigninSuggest> suggests = baseMapper.selectWeeklySuggestMap(patientId, startDate, endDate, types);
        if (CollectionUtil.isNotEmpty(suggests)) {
            return suggests.stream().collect(Collectors.groupingBy((d) -> DateUtils.getYearWeekStr(d.getRecordDate())));
        }
        return null;
    }

    @Override
    public boolean saveOrUpdateSuggestRecord(SigninSuggestBean suggest) {
        DtrdEntRdSigninSuggest po = new DtrdEntRdSigninSuggest();
        if (suggest.getDataId() == null) {
            po = po.init();
        }
        po = po.parseFromDTO(suggest);
//        Date recordDate = new Date();
//        if (!StrUtil.isBlank(suggest.getRecordDate())) {
//            recordDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//        }else {
//            recordDate = suggest.getRecordDate();
//        }
//        LambdaUpdateWrapper<DtrdEntRdSigninSuggest> updateWrapper = Wrappers.lambdaUpdate(DtrdEntRdSigninSuggest.class)
//                .eq(DtrdEntRdSigninSuggest::getRecordDate, recordDate)
//                .eq(DtrdEntRdSigninSuggest::getPatientId, suggest.getPatientId())
//                .eq(DtrdEntRdSigninSuggest::getSigninType, suggest.getSigninType());
        msgPusher.addSuggest(suggest.getSuggestContent(),suggest.getPatientId());
        return saveOrUpdate(po);
    }

    @Override
    public IPage<SigninSuggestBean> selectSigninSuggestPage(Integer pageNum, Integer pageSize, Integer patientId, String startDate, String endDate) {
        IPage<DtrdEntRdSigninSuggest> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<DtrdEntRdSigninSuggest> queryWrapper = getBaseQueryWrapper();
        if (patientId != 0) {
            queryWrapper.eq(DtrdEntRdSigninSuggest::getPatientId, patientId);
        }
        // 查询时间范围, between 是开区间
        queryWrapper.ge(DtrdEntRdSigninSuggest::getRecordTime, startDate)
                .le(DtrdEntRdSigninSuggest::getRecordTime, endDate)
                .orderByAsc(DtrdEntRdSigninSuggest::getPatientId)
                .orderByDesc(DtrdEntRdSigninSuggest::getRecordTime);
        IPage<DtrdEntRdSigninSuggest> queryPage = baseMapper.selectPage(page, queryWrapper);
        IPage<SigninSuggestBean> resultPage = null;
        if (CollectionUtil.isNotEmpty(queryPage.getRecords())) {
            resultPage = queryPage.convert(po -> new SigninSuggestBean().parseFromPO(po));
        }
        return resultPage;
    }

    @Override
    public boolean saveOrUpdateSuggestBatch(SigninSuggestDailyInfo info) {
        Integer patientId = info.getPatientId();
        String recordTime = info.getRecordTime();
        for (DtrdEntRdSigninSuggest po : info.toSuggestList()) {
            boolean result = this.saveOrUpdate(po, getUpdateWrapper(patientId, recordTime, po.getSigninType()));
            if (!result) {
                return false;
            }
        }
        return true;
    }

    @Override
    public SigninSuggestDailyInfo getSuggestRecord(DailyRequest request) {
        LambdaQueryWrapper<DtrdEntRdSigninSuggest> queryWrapper = getBaseQueryWrapper()
                .eq(DtrdEntRdSigninSuggest::getPatientId, request.getPatientId())
                .eq(DtrdEntRdSigninSuggest::getRecordTime, request.getQueryDate());
        List<DtrdEntRdSigninSuggest> poList = this.list(queryWrapper);
        SigninSuggestDailyInfo suggestDailyInfo = new SigninSuggestDailyInfo();
        poList.forEach(po -> {
            Constant.RecordType recordType = valueOf(po.getSigninType());
            // type 为 null 只能说明记录有问题
            assert recordType != null;
            switch (recordType) {
                case SUGAR:
                    suggestDailyInfo.setBloodSugarSuggest(po.getSuggestContent());
                    break;
                case BLOOD_PRESSURE:
                    suggestDailyInfo.setBloodPressureSuggest(po.getSuggestContent());
                    break;
                case SPORT:
                    suggestDailyInfo.setSportSuggest(po.getSuggestContent());
                    break;
                case MEDICAL:
                    suggestDailyInfo.setMedicalSuggest(po.getSuggestContent());
                    break;
                case DIET:
                    suggestDailyInfo.setDietSuggest(po.getSuggestContent());
                    break;
                case WEIGHT:
                    suggestDailyInfo.setBmiSuggest(po.getSuggestContent());
                    break;
                case WAIST:
                    suggestDailyInfo.setWaistSuggest(po.getSuggestContent());
                    break;
                case KETONE:
                    suggestDailyInfo.setKetoneSuggest(po.getSuggestContent());
                    break;
                case INSULIN:
                    suggestDailyInfo.setInsulinSuggest(po.getSuggestContent());
                    break;
                case SLEEP:
                    suggestDailyInfo.setSleepSuggest(po.getSuggestContent());
                    break;
                default:
                    break;
            }
        });
        return suggestDailyInfo;
    }

    @Override
    public DtrdEntRdSigninSuggest getLatestSuggest(Integer patientId, String date) {
        LambdaQueryWrapper<DtrdEntRdSigninSuggest> wrapper = getBaseQueryWrapper().eq(DtrdEntRdSigninSuggest::getPatientId, patientId).lt(DtrdEntRdSigninSuggest::getRecordDate, date).orderByDesc(DtrdEntRdSigninSuggest::getRecordTime).last(" limit 1");
        return getOne(wrapper);
    }

    @Override
    public List<ReportDrugSuggest> getDrudSuggestList(Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdSigninSuggest> queryWrapper = baseQueryWrapper(patientId)
                .eq(DtrdEntRdSigninSuggest::getSigninType, 4)
                .orderByAsc(DtrdEntRdSigninSuggest::getCreateTime);
        List<DtrdEntRdSigninSuggest> poList = list(queryWrapper);
        List<ReportDrugSuggest> dtoList = new ArrayList<>(poList.size());
        if (!poList.isEmpty()) {
            dtoList = poList.stream().map(po -> new ReportDrugSuggest().parseFromDTO(po)).collect(Collectors.toList());
        }
        return dtoList;
    }

    private LambdaQueryWrapper<DtrdEntRdSigninSuggest> getBaseQueryWrapper() {
        return Wrappers.lambdaQuery(DtrdEntRdSigninSuggest.class).eq(DtrdEntRdSigninSuggest::getIsDel, 0);
    }

    private LambdaUpdateWrapper<DtrdEntRdSigninSuggest> getUpdateWrapper(Integer patientId, String recordTime, Integer suggestType) {
        return Wrappers.lambdaUpdate(DtrdEntRdSigninSuggest.class)
                .eq(DtrdEntRdSigninSuggest::getPatientId, patientId)
                .eq(DtrdEntRdSigninSuggest::getSigninType, suggestType)
                .eq(DtrdEntRdSigninSuggest::getRecordTime, recordTime);
    }

    private LambdaQueryWrapper<DtrdEntRdSigninSuggest> baseQueryWrapper(Integer patientId) {
        return Wrappers.lambdaQuery(DtrdEntRdSigninSuggest.class)
                .eq(DtrdEntRdSigninSuggest::getPatientId, patientId)
                .eq(DtrdEntRdSigninSuggest::getIsDel, 0);
    }
}
